#include "cylinder.h"
#include <QtOpenGL>
#include <GL/glu.h>
#include <GL/glut.h>

Cylinder::Cylinder(const QVector3D& center, QObject *parent):Object3D(center, parent), height(2.0), radius(1.0)
{
}

void Cylinder::drawGeometry(void)
{
    glBindTexture(GL_TEXTURE_2D, texture());

    //setCenter(QVector3D(0.0, 0.0, -1));
    //glTranslatef(0.5,0.0,0.0);

    GLUquadric *quad = gluNewQuadric();
    if (getSelected()) {
        gluQuadricDrawStyle(quad, GLU_LINE);
    } else {
        gluQuadricDrawStyle(quad, GLU_FILL);
    }
    gluQuadricNormals(quad, GLU_SMOOTH);
    gluQuadricTexture(quad, true);

    glTranslatef(0.0,0.0,-height/2.0);
    gluQuadricOrientation(quad, GLU_OUTSIDE);
    gluCylinder(quad, radius, radius, height, 30, 30);

    gluQuadricOrientation(quad, GLU_INSIDE);
    gluDisk(quad, 0, radius, 20, 20);

    glTranslatef(0.0, 0.0, 2);
    gluQuadricOrientation(quad, GLU_OUTSIDE);
    gluDisk(quad, 0, radius, 20, 20);

    glBindTexture(GL_TEXTURE_2D, NULL);
}

float Cylinder::intersectionWithLine(QVector3D direction, QVector3D eye)
{
    // http://www.mrl.nyu.edu/~dzorin/rendering/lectures/lecture3/lecture3-6pp.pdf
    QVector3D worldCenter = center() + translation();
    QVector3D cylinderDirection(0.0,0.0,1.0);
    float scaledHeight = height*((float) getScaleFactor()/50);
    float scaledRadius = radius*((float) getScaleFactor()/50);
    //QVector3D p1 = worldCenter + *(new QVector3D(0.0, 0.0, -height/2.0));
    //QVector3D p2 = worldCenter + *(new QVector3D(0.0, 0.0, height/2.0));
    QVector3D p1(0.0, 0.0, -scaledHeight/2.0);
    QVector3D p2(0.0, 0.0, scaledHeight/2.0);

    cylinderDirection = interactiveQuartenion().rotatedVector(cylinderDirection);
    p1 = interactiveQuartenion().rotatedVector(p1);
    p2 = interactiveQuartenion().rotatedVector(p2);
    p1 += worldCenter;
    p2 += worldCenter;

    QVector3D deltaP = eye - p1;

    //QQuaternion t = interactiveQuartenion();
    //glRotatef(degreeFromCos(t.scalar()),t.x(), t.y(), t.z());


    //glMultMatrixd(rotations().constData());
    //interactiveQuartenion().rotatedVector(cylinderDirection)
    //cylinderDirection.toVector4D();
    //direction.normalize();

    QVector3D tmpA = cylinderDirection * QVector3D::dotProduct(direction, cylinderDirection);
    tmpA = direction - tmpA;
    QVector3D tmpB = cylinderDirection * QVector3D::dotProduct(deltaP, cylinderDirection);
    tmpB = deltaP - tmpB;

    float a = QVector3D::dotProduct(tmpA, tmpA);
    float b = QVector3D::dotProduct(tmpA, tmpB);
    float c = QVector3D::dotProduct(tmpB, tmpB) - scaledRadius*scaledRadius;
    float delta = b*b - a*c;
    float tMin = NULL;
    float t1, t2, t3, t4;

    if (delta >= 0.0) {
        delta = sqrt(delta);

        t1 = (-b + delta) / a;
        t2 = (-b - delta) / a;
        QVector3D q1 = eye + direction*t1;
        QVector3D q2 = eye + direction*t2;
        bool t1Test = QVector3D::dotProduct(cylinderDirection, q1 - p1) > 0 && QVector3D::dotProduct(cylinderDirection, q1 - p2) < 0;
        bool t2Test = QVector3D::dotProduct(cylinderDirection, q2 - p1) > 0 && QVector3D::dotProduct(cylinderDirection, q2 - p2) < 0;

        if (t1Test) {
            tMin = t1;
        }
        if (t2 < t1 && t2Test) {
            tMin = t2;
        }
    }

    float vaDotV = QVector3D::dotProduct(cylinderDirection, direction);

    if (vaDotV != 0) {
        t3 = (QVector3D::dotProduct(cylinderDirection, p1) - QVector3D::dotProduct(cylinderDirection, eye)) / vaDotV;
        t4 = (QVector3D::dotProduct(cylinderDirection, p2) - QVector3D::dotProduct(cylinderDirection, eye)) / vaDotV;
        QVector3D q3MinusP1 = (eye + direction*t3) - p1;
        QVector3D q4MinusP2 = (eye + direction*t4) - p2;
        bool t3Test = QVector3D::dotProduct(q3MinusP1, q3MinusP1) < scaledRadius*scaledRadius;
        bool t4Test = QVector3D::dotProduct(q4MinusP2, q4MinusP2) < scaledRadius*scaledRadius;

        if (t3Test && (tMin == NULL || t3 < tMin)) {
            tMin = t3;
        }
        if(t4Test  && (tMin == NULL || t4 < tMin)) {
            tMin = t4;
        }
    }

    return tMin;
}
